import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
import cv2
import time
print(cv2.__version__)
4.8.0
# 寫個函數方便之後使用
def show_(src, s=5, pr=1.5): # show the image
img = src.copy()
if np.dtype(img.dtype).kind == 'f': # 浮點數處理
pr_low = np.percentile(img, pr)
pr_high = np.percentile(img, 100-pr)
print(f'min: {img.min():.2f}, PR{pr}: {pr_low:.2f}, PR{100-pr}: {pr_high:.2f}, max: {img.max():.2f}')
img = img.clip(pr_low, pr_high)
plt.figure(figsize=(s, s))
plt.xticks([]), plt.yticks([])
plt.imshow(img)
plt.show()
else:
img = img.clip(0, 255).astype(np.uint8)
plt.figure(figsize=(s, s))
plt.xticks([]), plt.yticks([])
if img.ndim == 3: # color image
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # OpenCV 的色彩空間 BRG
plt.imshow(img)
else: # gray image
plt.imshow(img, cmap='gray')
plt.show()
def img_info(arr, text=None):
if text:
print(text)
print(f'shape: {arr.shape}\nmin: {arr.min()}\nmax: {arr.max()}\nmean: {arr.mean()}\nstd: {arr.std()}\ndtype: {arr.dtype}\n')
# 內建字體
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.imread(file_name, flag)¶| flag | / |
|---|---|
cv2.IMREAD_COLOR |
BGR (預設) |
cv2.IMREAD_GRAYSCALE |
灰階 |
cv2.IMREAD_UNCHANGED |
All channel BGR(A) |
b, g, r = cv2.split(img) 分出 B G R 跟一般RGB相反 cv2.merge((tuple 2D-array))img = cv2.imread('not exist') img == None
img = cv2.imread('data/p1.png')
# np.array
print('img-type: ', type(img))
b,g,r = cv2.split(img)
img2 = cv2.merge((b, g, r))
print('img same img2 ? ', np.all(img == img2))
img-type: <class 'numpy.ndarray'> img same img2 ? True
cv2.imshow(window_name, img)¶# 顯示圖片
cv2.imshow('My Image', img)
# 按下任意鍵則關閉所有視窗
while True:
k = cv2.waitKey(0) & 0xFF
if k == 27: # wait for ESC key to exit
break
elif k == ord('s'): # wait for 's' key to save and exit
cv2.imwrite('save.png', img)
break
else:
print('ESC key to exit, S key to save')
cv2.destroyAllWindows()
cv2.namedWindow(window_name, cv2.WINDOW_AUTOSIZE)¶cv2.imwrite('file_name.png', img)¶cv2.imwrite('file_name.jpg', img, [cv2.IMWRITE_JPEG_QUALITY, 90])
cv2.imwrite('file_name.png', img, [cv2.IMWRITE_PNG_COMPRESSION, 5])
cv2.cvtColor(img, flag) # 顏色空間轉換¶ColorConversionCodescv2.cvtColor(img, cv2.COLOR_BGR2RGB) 色彩空間轉換函數img = cv2.imread('data/fig1.jpg')
# 將 BGR 圖片轉為 RGB 圖片
# img = img[:,:,::-1]
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img)
plt.xticks([]), plt.yticks([])
# plt.show() # jupyter界面不用
(([], []), ([], []))
img = cv2.imread('data/fig1.jpg', cv2.IMREAD_GRAYSCALE)
# 單色指定cmap
plt.imshow(img, cmap='gray')
plt.xticks([]), plt.yticks([])
# plt.show() # jupyter界面不用
(([], []), ([], []))
# 自刻 可丟入一維
def gamma_correction(img, g=2.2):
out = img.copy()
out = out.astype(np.float64)
out /= 255.
out = out**(1/g)
out *= 255
out = out.astype(np.uint8)
return out
# 速度快很多 但是使用OpenCV lib 一定要輸入2dmin 影像
def gamma_correction2(img, gamma=2.2):
lookUpTable = (pow(np.arange(256) / 255, gamma) * 255).astype(np.uint8).reshape((1, 256))
res = cv2.LUT(img, lookUpTable)
return res
x = np.linspace(0, 255, 256)
plt.figure(figsize=(5, 5))
plt.plot(x, x, ':', linewidth=2.5)
# lst creat
neg_lst = np.power(np.linspace(0.1, 1, 9, endpoint=False), 2)
pos_lst = np.power(np.linspace(0.1, 1, 9, endpoint=False), -2)
for g in np.concatenate([pos_lst, neg_lst]):
plt.plot(x, gamma_correction(x, g), linewidth=1.5)
plt.xlim(0, 255)
plt.ylim(0, 255)
(0.0, 255.0)
img = cv2.imread('data/fig1.jpg')
show_(img)
gamma = gamma_correction(img, 2)
show_(gamma)
gamma = gamma_correction(img, 0.75)
show_(gamma)
Drawing Functions¶cv2.line(img, pt1, pt2, color, thickness)cv2.rectangle(img, pt1, pt2, color, thickness)cv2.circle(img, center, radius, color, thickness)cv2.ellipse(img, *args)cv2.polylines(img, pts, isClosed, color, thickness)cv2.putText(img, *args) 文字*args:color 顏色thickness 粗細 -1為封閉填滿linestyle# Create a black image
img = np.zeros((512, 512, 3), np.uint8)
cv2.line(img, (0, 0), (511, 511), (255, 0, 0), 5)
cv2.rectangle(img, (384, 0), (510, 128), (0, 255, 0), 3)
cv2.circle(img, (447, 63), 63, (0, 0, 255), -1)
cv2.ellipse(img, (256, 256), (100, 50), 0, 0, 180, 255, -1)
pts = np.array([[10, 5], [20, 30], [70, 20], [50, 10]], np.int32).reshape((-1, 1, 2))
cv2.polylines(img, [pts], True, (0, 255, 255))
cv2.putText(img, 'OpenCV', (10, 500), font, 4, (255, 255, 255), 2, cv2.LINE_AA)
show_(img, 4)
cv.setMouseCallback(window_name, MouseCallback(func)) Window 的滑鼠控制¶MouseCallback Obj (func)¶func(event, x, y, flags, param)for m in [i for i in dir(cv2) if 'EVENT' in i]:
print(m)
EVENT_FLAG_ALTKEY EVENT_FLAG_CTRLKEY EVENT_FLAG_LBUTTON EVENT_FLAG_MBUTTON EVENT_FLAG_RBUTTON EVENT_FLAG_SHIFTKEY EVENT_LBUTTONDBLCLK EVENT_LBUTTONDOWN EVENT_LBUTTONUP EVENT_MBUTTONDBLCLK EVENT_MBUTTONDOWN EVENT_MBUTTONUP EVENT_MOUSEHWHEEL EVENT_MOUSEMOVE EVENT_MOUSEWHEEL EVENT_RBUTTONDBLCLK EVENT_RBUTTONDOWN EVENT_RBUTTONUP
# mouse callback function
def draw_circle(event, x, y, flags, param):
if event == cv2.EVENT_FLAG_LBUTTON: # 左鍵單擊
cv2.circle(img, (x, y), 40, (255, 100, 100), -1)
# Create a black image, a window and bind the function to window
img = np.zeros((512, 512, 3), np.uint8)
cv2.namedWindow('image')
cv2.setMouseCallback('image', draw_circle)
while(1):
cv2.imshow('image', img)
if cv2.waitKey(20) & 0xFF == 27:
break
cv2.destroyAllWindows()
cv2.createTrackbar(trackbarname, window_name, default_value, max, func) # 創造調整條¶default_value : 初始值max : 最大值 最小為0func : 移動觸發的函數cv2.getTrackbarPos(trackbarname, window_name) # 調整條取值¶from time import sleep as slp
def nothing(x):
pass
# Create a black image, a window
img = np.zeros((400, 400, 3), np.uint8)
cv2.namedWindow('image') # create window
# create trackbars for color change
cv2.createTrackbar('R', 'image', 0, 8, nothing)
cv2.createTrackbar('G', 'image', 0, 8, nothing)
cv2.createTrackbar('B', 'image', 0, 8, nothing)
# create switch for ON/OFF functionality
switch = 'OFF - ON'
cv2.createTrackbar('OFF - ON', 'image', 0, 1, nothing)
while True:
slp(0.02)
cv2.imshow('image', img)
k = cv2.waitKey(1) & 0xFF
if k == 27:
break
# get current positions of four trackbars
r = cv2.getTrackbarPos('R', 'image')
g = cv2.getTrackbarPos('G', 'image')
b = cv2.getTrackbarPos('B', 'image')
s = cv2.getTrackbarPos(switch, 'image')
if s == 0:
img[:] = 0
else: # 閃爍燈
img[:] = img[:] + np.array([b, g, r])
cv2.destroyAllWindows()
cv2.BORDER_CONSTANT - Adds a constant colored border. The value should be given as next argument.cv2.BORDER_REFLECT - Border will be mirror reflection of the border elements, like this : fedcba|abcdefgh|hgfedcbcv2.BORDER_REFLECT_101 - or cv.BORDER_DEFAULT - Same as above, but with a slight change, like this : gfedcb|abcdefgh|gfedcbacv2.BORDER_REPLICATE - Last element is replicated throughout, like this: aaaaaa|abcdefgh|hhhhhhhcv2.BORDER_WRAP - Can't explain, it will look like this : cdefgh|abcdefgh|abcdefgimg = cv2.imread('data/p4.png')[:, :, ::-1]
replicate = cv2.copyMakeBorder(img, 40, 40, 40, 40, cv2.BORDER_REPLICATE)
reflect = cv2.copyMakeBorder(img, 40, 40, 40, 40, cv2.BORDER_REFLECT)
reflect101 = cv2.copyMakeBorder(img, 40, 40, 40, 40, cv2.BORDER_REFLECT_101)
wrap = cv2.copyMakeBorder(img, 40, 40, 40, 40, cv2.BORDER_WRAP)
constant = cv2.copyMakeBorder(img, 40, 40, 40, 40, cv2.BORDER_CONSTANT, value=[0, 0, 0])
plt.figure(figsize=(10, 6))
plt.subplot(231), plt.imshow(img, 'gray'), plt.title('ORIGINAL'), plt.xticks([]), plt.yticks([])
plt.subplot(232), plt.imshow(replicate, 'gray'), plt.title('REPLICATE'), plt.xticks([]), plt.yticks([])
plt.subplot(233), plt.imshow(reflect, 'gray'), plt.title('REFLECT'), plt.xticks([]), plt.yticks([])
plt.subplot(234), plt.imshow(reflect101, 'gray'), plt.title('REFLECT_101'), plt.xticks([]), plt.yticks([])
plt.subplot(235), plt.imshow(wrap, 'gray'), plt.title('WRAP'), plt.xticks([]), plt.yticks([])
plt.subplot(236), plt.imshow(constant, 'gray'), plt.title('CONSTANT'), plt.xticks([]), plt.yticks([])
(<AxesSubplot:title={'center':'CONSTANT'}>,
<matplotlib.image.AxesImage at 0x1fa033cc280>,
Text(0.5, 1.0, 'CONSTANT'),
([], []),
([], []))
cv2.add(img1, img2)¶np.minimun(arr, 255)cv2.addWeighted(img1, 𝛼, img2, 𝛽, 𝛾) 圖片疊加 (權重)¶img1 = 50 * np.ones((300, 300, 3), np.uint8)
img2 = 100 * np.ones_like(img1, np.uint8)
img = cv2.add(img1, img2)
show_(img, 2)
img = cv2.addWeighted(img1, 0.8, img2, 0.4, 5) # 50*0.8 + 100*0.4 + 5 = 85
print(img[0, 0, 0])
show_(img, 2)
85
cv2.resize(img, (w, h), fx, fy, interpolation)¶cv2.resize(img, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)cv2.resize(img, (width, height), interpolation=cv2.INTER_CUBIC)interpolation 縮放的演算法選擇cv2.INTER_CUBIC(慢), cv2.INTER_LINEAR(預設)cv2.INTER_AREAimg = cv2.imread('data/fig1.jpg')
img2 = cv2.resize(img, (500, 250), interpolation=cv2.INTER_CUBIC)
show_(img2, 3)
print(img.shape)
print(img2.shape)
(920, 1272, 3) (250, 500, 3)
cv2.warpAffine(img, M, (width, height)) 線性轉換¶公式
OpenCV 可自訂旋轉中心點:
scale(float) 執行縮放cv2.getAffineTransform(pts1, pts2) 來產生這個矩陣
M = np.float32([[1, 0, 300], [0, 1, 150]]) # np.float32
h, w = img.shape[0:2]
img3 = cv2.warpAffine(img, M, (w, h))
show_(img3, 4)
M = cv2.getRotationMatrix2D((w/2 +100, h/2-100), 45, 1)
img3 = cv2.warpAffine(img, M, (w, h))
show_(img3, 4)
# Affine Transformation
img = cv2.imread('data/fig1.jpg')
pts1 = np.float32([[100, 100], [100, 600], [600, 100]])
pts2 = np.float32([[200, 200], [300, 800], [900, 300]])
M = cv2.getAffineTransform(pts1, pts2)
s = 7
for arr in pts1:
i, j = np.int64(arr)
img[i-s:i+s+1, j-s:j+s+1] = [0, 255, 255]
show_(img, 4)
img4 = cv2.warpAffine(img, M, (w, h))
show_(img4, 4)
cv2.warpPerspective(img, M, (width, height))¶cv2.getPerspectiveTransform(pts1, pts2) 生成矩陣
# Perspective Transformation
img = cv2.imread('data/fig1.jpg')
pts1 = np.float32([[46, 75], [830, 152], [75, 357], [880, 859]])
pts2 = np.float32([[0, 0], [600, 0], [0, 600], [600, 600]])
M = cv2.getPerspectiveTransform(pts1, pts2)
s = 10
for arr in pts1:
i, j = np.int64(arr)
img[i-s:i+s+1, j-s:j+s+1] = [0, 255, 255]
show_(img, 4)
img5 = cv2.warpPerspective(img, M, (700, 700))
show_(img5, 4)
cv2.threshold(img, thresh, maxval, type ) 簡單閥值¶thresh 基準值macxval 最大值(cv2.THRESH_BINARY, cv2.THRESH_BINARY_INV 專用)output : retval, dstThreshold Types¶
x = np.linspace(0, 2 * np.pi, 1000)
img = np.uint8(((np.sin(x) + 1) / 2) * 255)
thresh = 100
maxval = 255
ret, thresh1 = cv2.threshold(img, thresh, maxval, cv2.THRESH_BINARY)
ret, thresh2 = cv2.threshold(img, thresh, maxval, cv2.THRESH_BINARY_INV)
ret, thresh3 = cv2.threshold(img, thresh, -1, cv2.THRESH_TRUNC)
ret, thresh4 = cv2.threshold(img, thresh, -1, cv2.THRESH_TOZERO)
ret, thresh5 = cv2.threshold(img, thresh, -1, cv2.THRESH_TOZERO_INV)
titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
for i in range(6):
plt.figure(figsize=(12, 1.5))
if i == 0:
plt.plot(thresh * np.ones(1000), lw=2)
plt.plot(images[i], lw=2)
plt.title(titles[i])
plt.ylim(-5, 260)
plt.xticks([])
plt.show()
img = np.uint8(np.zeros((256, 256)))
for i in range(256):
img[i, :] = i
thresh = 127
maxval = 255
ret, thresh1 = cv2.threshold(img, thresh, maxval, cv2.THRESH_BINARY)
ret, thresh2 = cv2.threshold(img, thresh, maxval, cv2.THRESH_BINARY_INV)
ret, thresh3 = cv2.threshold(img, thresh, maxval, cv2.THRESH_TRUNC)
ret, thresh4 = cv2.threshold(img, thresh, maxval, cv2.THRESH_TOZERO)
ret, thresh5 = cv2.threshold(img, thresh, maxval, cv2.THRESH_TOZERO_INV)
titles = ['Original Image', 'BINARY', 'BINARY_INV', 'TRUNC', 'TOZERO', 'TOZERO_INV']
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
plt.figure(figsize=(10, 6))
for i in range(6):
plt.subplot(2, 3, i + 1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
cv2.adaptiveThreshold(img, maxValue, adaptiveMethod, thresholdType, blockSize, C) 自動閥值¶adaptiveMethodcv2.ADAPTIVE_THRESH_MEAN_C 閥值取決filter平均值cv2.ADPTIVE_THRESH_GAUSSIAN_C 閥值取決filter 的高斯window
img = cv2.imread('data/fig2.jpg', 0)
img = cv2.medianBlur(img, 5)
ret, th1 = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY)
th2 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 99, 2)
th3 = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY, 99, 2)
titles = ['Original Image', 'Global Thresholding (v = 127)',
'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
images = [img, th1, th2, th3]
plt.figure(figsize=(10, 8))
for i in range(4):
plt.subplot(2, 2, i + 1), plt.imshow(images[i], 'gray')
plt.title(titles[i])
plt.xticks([]), plt.yticks([])
cv2.GaussianBlur(img, ksize, sigmaX,) # Gaussian filter 高斯濾鏡¶cv.THRESH_OTSU Otsu's 二值化¶img = np.maximum(np.random.normal(75, 20, (300, 400)), 0)
img[75:225, 75:325] = np.minimum(np.random.normal(150, 20, (150, 250)), 255)
img = np.uint8(img)
# global thresholding
ret1, th1 = cv2.threshold(img, 100, 255, cv2.THRESH_BINARY)
# Otsu's thresholding # thresh 設定為0, cv2.THRESH_OTSU 會自動找到最佳值
ret2, th2 = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# Otsu's thresholding after Gaussian filtering # thresh 設定為0, cv2.THRESH_OTSU 會自動找到最佳值
blur = cv2.GaussianBlur(img, (9, 9), 0)
ret3, th3 = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
# plot all the images and their histograms
images = [img, 0, th1,
img, 0, th2,
blur, 0, th3]
titles = ['Original Noisy Image', 'Histogram', 'Global Thresholding (v=127)',
'Original Noisy Image', 'Histogram', "Otsu's Thresholding",
'Gaussian filtered Image', 'Histogram', "Otsu's Thresholding"]
plt.figure(figsize=(12, 8))
for i in range(3):
plt.subplot(3, 3, i * 3 + 1), plt.imshow(images[i * 3], 'gray')
plt.title(titles[i * 3]), plt.xticks([]), plt.yticks([])
plt.subplot(3, 3, i * 3 + 2), plt.hist(images[i * 3].ravel(), 256, [0, 256])
plt.title(titles[i * 3 + 1]), plt.xticks([]), plt.yticks([])
plt.subplot(3, 3, i * 3 + 3), plt.imshow(images[i * 3 + 2], 'gray')
plt.title(titles[i * 3 + 2]), plt.xticks([]), plt.yticks([])
cv2.bitwise # 二進位邏輯運算¶_and(arr1, arr2, mask) == arr1 & arr2 if mask > 1_not(arr1, mask) == ~arr if mask > 1_or(arr1, arr2, mask) == arr1 | arr2 if mask > 1_xor(arr1, arr2, mask) == arr1 ^ arr2 if mask > 1# Load two images
img1 = cv2.imread('data/fig1.jpg')
img2 = cv2.imread('data/fig2.jpg')
# Now create a mask of logo and create its inverse mask also
img2gray = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
ret, mask = cv2.threshold(img2gray, 128, 256, cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)
# Now black-out the area of logo in ROI
img1_bg = cv2.bitwise_and(img1, img1, mask=mask_inv) # 速度比較快
# img1_bg = (img1.transpose(2, 0, 1) * mask_inv).transpose(1, 2, 0)
# Take only region of logo from logo image.
img2_fg = cv2.bitwise_and(img2, img2, mask=mask)
# img2_bg = (img2.transpose(2, 0, 1) * mask).transpose(1, 2, 0)
# Put logo in ROI and modify the main image
img = cv2.add(img1_bg, img2_fg)
#show
show_(img1_bg, 4)
show_(img2_fg, 4)
show_(img, 4)
$K = \frac{1}{9} \begin{bmatrix} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \end{bmatrix}$
cv2.filter2D(img, ddepth, kernel, outimg)¶ddepth (when ddepth=-1, the output image will have the same depth as the source.) 設定-1 會和img預設一樣kernel (2D np.array) 濾鏡自己寫img = cv2.imread('data/p1.png')
kernel = np.ones((2, 12)) / 24 # 不設定正方形 有單邊模糊的感覺(速度感)
dst = cv2.filter2D(img, -1, kernel)
plt.figure(figsize=(10, 6))
plt.subplot(121), plt.imshow(img), plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(dst), plt.title('Filter2D')
plt.xticks([]), plt.yticks([])
(([], []), ([], []))
cv2.blur(img, ksize(m, n)) # 模糊濾鏡 Averaging¶blur = cv2.blur(img, (5, 5))
plt.figure(figsize=(10, 6))
plt.subplot(121), plt.imshow(img), plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(blur), plt.title('Blurred')
plt.xticks([]), plt.yticks([])
(([], []), ([], []))
cv2.GaussianBlur(img, ksize (m, n), sigmaX, sigmaY=0) # 高斯濾鏡 Gaussian Blurring¶cv2.getGaussianKernel(ksize (int), sigma) 可以生成高斯濾鏡blur = cv2.GaussianBlur(img, (5, 5), 1)
plt.figure(figsize=(10, 6))
plt.subplot(121), plt.imshow(img), plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(blur), plt.title('Gaussian Blurring')
plt.xticks([]), plt.yticks([])
(([], []), ([], []))
for i in [15, 25, 35]:
kernel = cv2.getGaussianKernel(i, 5) # 生成高斯濾鏡
kernel = kernel * kernel.T
plt.imshow(kernel)
plt.show()
for i in [15, 25, 35]:
kernel = cv2.getGaussianKernel(i, 0) # 生成高斯濾鏡
kernel = kernel * kernel.T
plt.imshow(kernel)
plt.show()
kernel = cv2.getGaussianKernel(5, 1) # 生成高斯濾鏡
kernel = kernel * kernel.T # 轉換成 5x5
dst = cv2.filter2D(img, -1, kernel)
plt.figure(figsize=(10, 6))
plt.subplot(121), plt.imshow(img), plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(dst), plt.title('Gaussian Blurring')
plt.xticks([]), plt.yticks([])
(([], []), ([], []))
cv2.medianBlur(img, ksize (int)) # 中值濾鏡 Median Blurring¶max 最大值 (形態學, 膨脹)min 最小值 (形態學, 腐蝕)median 中位數 (適合處理脈衝雜訊)img = cv2.imread('data/p1.png')
# 增加noise
noise_filter = np.random.uniform(0 , 1, size=(img.shape[:2])) < 0.05
noise = np.uint8(np.random.uniform(0, 255, size=(img.shape)))
img[noise_filter] = noise[noise_filter]
show_(img)
median = cv2.medianBlur(img, 3)
plt.figure(figsize=(10, 6))
plt.subplot(121), plt.imshow(img), plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(median), plt.title('Median')
plt.xticks([]), plt.yticks([])
(([], []), ([], []))
cv.bilateralFilter(img, d, sigmaColor, sigmaSpace, borderType=BORDER_DEFAULT ) # 雙邊過濾 Bilateral Filtering¶
img = cv2.imread('data/tiger.jpg')
blur = cv2.bilateralFilter(img, 15, 75, 75)
plt.figure(figsize=(10, 6))
plt.subplot(121), plt.imshow(img), plt.title('Original')
plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(blur), plt.title('Bilateral')
plt.xticks([]), plt.yticks([])
(([], []), ([], []))
cv2.erode(img, kernel, iterations(int)) 腐蝕¶iterations: 迭代次數cv2.dilate(img, kernel, iterations(int)) 膨脹¶iterations: 迭代次數cv2.morphologyEx(img, op, kernel, iterations(int))¶iterations: 迭代次數op_typecv2.MORPH_OPEN 先腐蝕再膨脹cv2.MORPH_CLOSE 先膨脹再腐蝕cv2.MORPH_GRADIENT 膨脹和腐蝕差異img = cv2.imread('data/p.png', 0)
img = cv2.bitwise_not(img)
show_(img, 3)
kernel = np.ones((5, 5), np.uint8)
erosion = cv2.erode(img, kernel, iterations=1)
show_(erosion, 3)
dilation = cv2.dilate(img, kernel, iterations=1)
show_(dilation, 3)
# 把雜訊吃掉, 吃掉白雜訊
noise = np.uint8((np.random.uniform(size=img.shape) > 0.85 ) * 255)
img_ = cv2.add(img, noise)
opening = cv2.morphologyEx(img_, cv2.MORPH_OPEN, kernel)
# res = cv2.erode(img_, kernel, iterations=1)
# res = cv2.dilate(res, kernel, iterations=1)
show_(img_, 3)
show_(opening, 3)
# show_(res, 3)
# 把雜訊吃掉, 吃掉黑雜訊
noise = np.uint8((np.random.uniform(size=img.shape) > 0.15 ) * 255)
img_ = cv2.bitwise_and(img, noise, mask=img)
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
# res = cv2.dilate(img_, kernel, iterations=1)
# res = cv2.erode(res, kernel, iterations=1)
show_(img_, 3)
show_(closing, 3)
# show_(res, 3)
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
show_(gradient, 3)
show_((erosion != dilation) * 255, 3)
cv2.getStructuringElement(Morph-shape, ksize (tuple)) # 生成結構 kernel¶$K = \begin{bmatrix} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \end{bmatrix}$
- shape:
MorphShapes(0~2)- All 1, 認定 0 or 1
- 多於 1個 1, 認定 0 or 1
- 同樣可以消除noise
- 輪廓, 以上兩種的相反型態
cv2.MORPH_ELLIPSE是橢圓形 要圓形可以用兩個橢圓疊起來XD
arr = cv2.getStructuringElement(cv2.MORPH_RECT, (11, 11))
print(arr)
[[1 1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1 1]]
arr = cv2.getStructuringElement(cv2.MORPH_CROSS, (11, 11))
print(arr)
[[0 0 0 0 0 1 0 0 0 0 0] [0 0 0 0 0 1 0 0 0 0 0] [0 0 0 0 0 1 0 0 0 0 0] [0 0 0 0 0 1 0 0 0 0 0] [0 0 0 0 0 1 0 0 0 0 0] [1 1 1 1 1 1 1 1 1 1 1] [0 0 0 0 0 1 0 0 0 0 0] [0 0 0 0 0 1 0 0 0 0 0] [0 0 0 0 0 1 0 0 0 0 0] [0 0 0 0 0 1 0 0 0 0 0] [0 0 0 0 0 1 0 0 0 0 0]]
arr = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11, 11))
print(arr)
[[0 0 0 0 0 1 0 0 0 0 0] [0 0 1 1 1 1 1 1 1 0 0] [0 1 1 1 1 1 1 1 1 1 0] [1 1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1 1] [0 1 1 1 1 1 1 1 1 1 0] [0 0 1 1 1 1 1 1 1 0 0] [0 0 0 0 0 1 0 0 0 0 0]]
k = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11, 11))
print(k & k.T)
[[0 0 0 0 0 1 0 0 0 0 0] [0 0 1 1 1 1 1 1 1 0 0] [0 1 1 1 1 1 1 1 1 1 0] [0 1 1 1 1 1 1 1 1 1 0] [0 1 1 1 1 1 1 1 1 1 0] [1 1 1 1 1 1 1 1 1 1 1] [0 1 1 1 1 1 1 1 1 1 0] [0 1 1 1 1 1 1 1 1 1 0] [0 1 1 1 1 1 1 1 1 1 0] [0 0 1 1 1 1 1 1 1 0 0] [0 0 0 0 0 1 0 0 0 0 0]]
k = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11, 11))
print(k | k.T)
[[0 0 0 1 1 1 1 1 0 0 0] [0 0 1 1 1 1 1 1 1 0 0] [0 1 1 1 1 1 1 1 1 1 0] [1 1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1 1] [1 1 1 1 1 1 1 1 1 1 1] [0 1 1 1 1 1 1 1 1 1 0] [0 0 1 1 1 1 1 1 1 0 0] [0 0 0 1 1 1 1 1 0 0 0]]
Sobel & Scharrcv2.Sobel(img, ddepth, dx, dy, ksize (int)) Gausssian smoothing plus differentiation operation¶cv2.Scharr(img, ddepth, dx, dy)¶cv2.Laplacian(img, ddepth, ksize (int)) 二階導數¶ddepth¶-1 (和原始圖形相同)img = cv2.imread('data/dave.jpg',0)
laplacian = cv2.Laplacian(img, cv2.CV_64F, ksize=5)
sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=5)
sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=5)
scharrx = cv2.Scharr(img, cv2.CV_64F, 1, 0)
scharry = cv2.Scharr(img, cv2.CV_64F, 0, 1)
plt.figure(figsize=(8, 12))
plt.subplot(3, 2, 1), plt.imshow(img, cmap='gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(3, 2, 2), plt.imshow(laplacian, cmap='gray', vmin=0, vmax=255)
plt.title('Laplacian'), plt.xticks([]), plt.yticks([])
plt.subplot(3, 2, 3), plt.imshow(sobelx, cmap='gray', vmin=0, vmax=255)
plt.title('Sobel X'), plt.xticks([]), plt.yticks([])
plt.subplot(3, 2, 4), plt.imshow(sobely, cmap='gray', vmin=0, vmax=255)
plt.title('Sobel Y'), plt.xticks([]), plt.yticks([])
plt.subplot(3, 2, 5), plt.imshow(scharrx, cmap='gray', vmin=0, vmax=255)
plt.title('Scharr X'), plt.xticks([]), plt.yticks([])
plt.subplot(3, 2, 6), plt.imshow(scharry, cmap='gray', vmin=0, vmax=255)
plt.title('Scharr Y'), plt.xticks([]), plt.yticks([])
(Text(0.5, 1.0, 'Scharr Y'), ([], []), ([], []))
img = np.zeros((200, 200), np.uint8)
img[50:150, 50:150] = 255
# Output dtype = cv2.CV_8U
sobelx8u = cv2.Sobel(img, cv2.CV_8U, 1, 0, ksize=5)
# Output dtype = cv2.CV_64F. Then take its absolute and conv2ert to cv2.CV_8U
sobelx64f = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=5)
abs_sobel64f = np.absolute(sobelx64f)
sobel_8u = np.uint8(abs_sobel64f)
plt.figure(figsize=(10, 6))
plt.subplot(1, 3, 1), plt.imshow(img, cmap='gray')
plt.title('Original'), plt.xticks([]), plt.yticks([])
plt.subplot(1, 3, 2), plt.imshow(sobelx8u, cmap='gray')
plt.title('Sobel CV_8U'), plt.xticks([]), plt.yticks([])
plt.subplot(1, 3, 3), plt.imshow(sobel_8u, cmap='gray')
plt.title('Sobel abs(CV_64F)'), plt.xticks([]), plt.yticks([])
(Text(0.5, 1.0, 'Sobel abs(CV_64F)'), ([], []), ([], []))
img = cv2.imread('data/wild.png', 0)
edges = cv2.Canny(img, 100, 120)
plt.figure(figsize=(10, 6))
plt.subplot(121), plt.imshow(img, cmap='gray')
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(edges, cmap='gray')
plt.title('Edge Image'), plt.xticks([]), plt.yticks([])
plt.show()
cv2.pyrDown(img, dstsize, borderType)¶*args:dstsize :輸出設定borderType :邊界設定cv2.pyrUp(img, dstsize, borderType)¶*args:dstsize :輸出設定borderType :邊界設定img = cv2.imread('data/corner.jpg', 0)
img_info(img)
show_(img, 4)
# 製作kernel
ar = np.array([[1, 4, 6, 4, 1]])
kernel = (ar * ar.T) / 256
img_ = cv2.filter2D(img, -1, kernel)
img_ = img_[::2, ::2]
img_info(img_)
show_(img_, 4)
shape: (256, 256) min: 0 max: 252 mean: 182.8223876953125 std: 62.68371200514711 dtype: uint8
shape: (128, 128) min: 28 max: 243 mean: 182.87127685546875 std: 61.710469936516084 dtype: uint8
show_(img, 4)
# Gaussian Pyramid
img_G1 = cv2.pyrDown(img)
show_(img_G1, 4)
# Laplacian Pyramids
img_L = cv2.subtract(img, cv2.pyrUp(img_G1))
plt.imshow(img_L)
<matplotlib.image.AxesImage at 0x1fa03743c10>
A = cv2.imread('data/apple.jpg')
B = cv2.imread('data/orange.jpg')
# generate Gaussian pyramid
G = A.copy()
gpA = [A.copy()]
gpB = [B.copy()]
for i in range(6):
gpA.append(cv2.pyrDown(gpA[i]))
gpB.append(cv2.pyrDown(gpB[i]))
# generate Laplacian Pyramid
lpA = [gpA[5]]
lpB = [gpB[5]]
for i in range(5, 0, -1):
L = cv2.subtract(gpA[i - 1], cv2.pyrUp(gpA[i]))
lpA.append(L)
L = cv2.subtract(gpB[i - 1], cv2.pyrUp(gpB[i]))
lpB.append(L)
# Now add left and right halves of images in each level
LS = []
for la, lb in zip(lpA, lpB):
rows, cols, dpt = la.shape
ls = np.hstack((la[:, 0:cols // 2], lb[:, cols // 2:]))
LS.append(ls)
# now reconstruct
ls_ = LS[0]
for i in range(1, 6):
ls_ = cv2.pyrUp(ls_)
ls_ = cv2.add(ls_, LS[i])
# image with direct connecting each half
real = np.hstack((A[:, :cols // 2], B[:, cols // 2:]))
show_(ls_, 4)
show_(real, 4)
cv2.findContours(img (8-bit), mode, method) 尋找輪廓¶mode 輪廓檢索模式 解釋method 輪廓近似方法cv2.CHAIN_APPROX_NONE 所有點位cv2.CHAIN_APPROX_SIMPLE 線段只存兩端點output : contours, hierarchycontous(list) 輪廓, 幾個輪廓就幾項 (白色部份), np.array 所有邊界的座標hierarchy 輪廓層級
### cv2.drawContours(image, contours (list), contour_index, color (0-255), thickness=1) 畫出輪廓contours cv2.findContours's outputcontour_index 指定index (-1 畫出全部)
[Next, Previous, First_Child, Parent]Next 同級的下一個輪廓, 最後一個同級輪廓顯示-1Previous 同級前一個輪廓, 第一個同級輪廓顯示-1First_Child 第一個子輪廓Parent 父輪廓cv2.RETR_LIST 所有輪廓都為同等級不分父子[?, ?, -1, -1]cv2.RETR_EXTERNAL 只回傳0級(最外層)忽略所有子輪廓cv2.RETR_CCOMP 限定只分級兩層結構
cv2.RETR_TREE 完整的分層結構
img = cv2.imread('data/p2.png')
img_ = np.copy(img)
ret, thresh = cv2.threshold(img_[:, :, 0], 95, 255, cv2.THRESH_BINARY)
show_(thresh, 5)
# 版本別 output會有三項(v3.4) v4.2有兩項
# image, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print('contours number:', len(contours))
cv2.drawContours(img_, contours, -1, (25, 240, 40), 3)
show_(img_, 5)
contours number: 3
cv2.moment(contour) 輪廓抓取資料分析¶cv2.contourArea(contour) 面積計算, M['m00']¶cv2.arcLength(contour, close 閉合否(bool)) 週長計算¶img_ = np.copy(img)
cnt = contours[2]
M = cv2.moments(cnt)
cx = int(M['m10'] / M['m00'])
cy = int(M['m01'] / M['m00'])
cv2.drawContours(img_, [cnt], 0, (25, 240, 40), 3)
img_[cy-5:cy+5, cx-5:cx+5] = (0, 0, 255) # 質心
show_(img_, 5)
area = cv2.contourArea(cnt)
perimeter = cv2.arcLength(cnt, True)
print('Area: ', area)
print('Perimeter: ', perimeter)
Area: 51867.0 Perimeter: 1341.3666543960571
cv2.approxPolyDP(contour, epsilon, closed(bool)) 輪廓近似¶np.array(contour)cv2.arcLength(cnt,True))img_ = np.copy(img)
cnt = contours[2]
L = cv2.arcLength(cnt, True)
approx = cv2.approxPolyDP(cnt, L*0.01, True)
cv2.drawContours(img_, [approx], 0, (50, 255, 50), 3)
show_(img_, 5)
print('cnt pts:', cnt.shape[0])
print('approx pts:', approx.shape[0])
cnt pts: 601 approx pts: 16
cv2.convexHull(contour) # 凸包¶cv2.isContourConvex(contour) # 檢查是否凸包¶img_ = np.copy(img)
cnt = contours[2]
hull = cv2.convexHull(cnt)
cv2.drawContours(img_, [hull], -1, (255, 0, 255), 3)
cnt = contours[0]
r_hull = cv2.convexHull(cnt, returnPoints=False)
cv2.drawContours(img_, cnt[r_hull[:, 0]], -1, (25, 255, 25), 5)
show_(img_, 5)
print('cnt is convex? ', cv2.isContourConvex(cnt))
print('cnt is convex? ', cv2.isContourConvex(hull))
cnt is convex? False cnt is convex? True
cv2.boundingRect(contour)¶img_ = np.copy(img)
cnt = contours[0]
x, y, w, h = cv2.boundingRect(cnt)
cv2.rectangle(img_, (x, y), (x + w, y + h), (0, 255, 0), 5)
show_(img_, 5)
img_ = np.copy(img)
cnt = contours[0]
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int64(box)
cv2.drawContours(img_, [box], 0, (0, 255, 0), 5)
show_(img_, 5)
img_ = np.copy(img)
cnt = contours[2]
(x, y), radius = cv2.minEnclosingCircle(cnt)
center = (int(x), int(y))
radius = int(radius)
cv2.circle(img_, center, radius, (0, 255, 0), 5)
show_(img_, 5)
img_ = np.copy(img)
cnt = contours[0]
ellipse = cv2.fitEllipse(cnt)
cv2.ellipse(img_, ellipse, (0, 255, 0), 5)
show_(img_, 5)
img_ = np.copy(img)
cnt = contours[0]
rows, cols = img.shape[:2]
[vx, vy, x, y] = cv2.fitLine(cnt, cv2.DIST_L2, 0, 0.01, 0.01)
lefty = int((-x * vy / vx) + y)
righty = int(((cols - x) * vy / vx) + y)
cv2.line(img_, (cols - 1, righty), (0, lefty), (0, 255, 0), 5)
show_(img_, 5)
cv2.pointPolygonTest(contour, pt, measureDist) # 測試點在輪廓的位置¶# 適用於凸包的輪廓 非凸包可能找到local maximum
def GetInsideCircleInfo(cnt, acc=1):
x, y = cnt.mean(0)[0] # 粗算輪廓重心
val = cv2.pointPolygonTest(cnt, (x, y), True)
while True:
# 檢驗圓心有沒有變
x_ = x
y_ = y
if val == 0: # 在輪廓上
break
# 找尋 X 左右誰大
tmp = cv2.pointPolygonTest(cnt, (x + acc, y), True)
if tmp > val:
val = tmp
x += acc
else:
tmp = cv2.pointPolygonTest(cnt, (x - acc, y), True)
if tmp > val:
val = tmp
x -= acc
# 找尋 Y 上下誰大
tmp = cv2.pointPolygonTest(cnt, (x, y + acc), True)
if tmp > val:
val = tmp
y += acc
else:
tmp = cv2.pointPolygonTest(cnt, (x, y - acc), True)
if tmp > val:
val = tmp
y -= acc
if x == x_ and y == y_:
if acc < 0.1: # 精度夠了跳出
break
acc /= 2 # 精度更細
return (x, y), val
img_ = np.copy(img)
cnt = contours[2]
(x_, y_), radius_ = cv2.minEnclosingCircle(cnt) # 外接圓
center_ = (int(x_), int(y_))
radius_ = int(radius_)
(x, y), radius = GetInsideCircleInfo(cnt) # 內接圓
center = (int(x), int(y))
radius = int(radius)
cv2.circle(img_, center_, radius_, (0, 255, 0), 5)
cv2.circle(img_, center, radius, (0, 0, 255), 5)
show_(img_, 5)
cv2.HuMoments(moments) # 計算Hu 矩¶cv2.matchShapes(contour1, contour2, method, 0(not supported now)) # 計算輪廓形狀相似性¶*args:contour1, contour2 :輸入可以是8 bit, 也可以是輪廓 contourmethod : cv2.CONTOURS_MATCH_I1 ~ 3# 自刻
def get_HuM(img:np.array):
M = cv2.moments(img, False)
HuM = cv2.HuMoments(M)
res = -np.sign(HuM) * np.log(np.abs(HuM))
return res
img = np.zeros((200, 200), np.uint8)
cv2.putText(img, '&', (35, 150), font, 5, 255, 15, cv2.LINE_AA)
show_(img, 2)
img2 = np.zeros((200, 200), np.uint8)
cv2.putText(img2, '&', (25, 170), font, 3, 255, 9, cv2.LINE_AA)
show_(img2, 2)
# 三種誤差函數
print(cv2.matchShapes(img, img2, cv2.CONTOURS_MATCH_I1, 0))
print(cv2.matchShapes(img, img2, cv2.CONTOURS_MATCH_I2, 0))
print(cv2.matchShapes(img, img2, cv2.CONTOURS_MATCH_I3, 0))
print('========================================================')
HuM = get_HuM(img)
resize_HuM = get_HuM(img2)
df = pd.DataFrame.from_dict({'HuM':HuM[:, 0], 'resize_HuM':resize_HuM[:, 0]})
df.head(7)
0.0032258626948472036 0.028538103434744055 0.009640930835552328 ========================================================
| HuM | resize_HuM | |
|---|---|---|
| 0 | 6.815878 | 6.881590 |
| 1 | 17.904620 | 18.083721 |
| 2 | 22.489218 | 22.702497 |
| 3 | 27.849101 | 28.033127 |
| 4 | 53.635309 | 53.870010 |
| 5 | -37.040125 | -37.361969 |
| 6 | 53.190280 | 53.649199 |
img = np.zeros((200, 200), np.uint8)
cv2.putText(img, '&', (35, 150), font, 5, 255, 15, cv2.LINE_AA)
show_(img, 2)
M = cv2.getRotationMatrix2D((100, 100), -120, 1)
img2 = cv2.warpAffine(img, M, (200, 200))
show_(img2, 2)
# 三種誤差函數
print(cv2.matchShapes(img, img2, cv2.CONTOURS_MATCH_I1, 0))
print(cv2.matchShapes(img, img2, cv2.CONTOURS_MATCH_I2, 0))
print(cv2.matchShapes(img, img2, cv2.CONTOURS_MATCH_I3, 0))
print('========================================================')
HuM = get_HuM(img)
rot_HuM = get_HuM(img2)
df = pd.DataFrame.from_dict({'HuM':HuM[:, 0], 'rot_HuM':rot_HuM[:, 0]})
df.head(7)
6.488362956080795e-06 5.68511266818561e-05 1.920582359357875e-05 ========================================================
| HuM | rot_HuM | |
|---|---|---|
| 0 | 6.815878 | 6.815747 |
| 1 | 17.904620 | 17.906153 |
| 2 | 22.489218 | 22.488741 |
| 3 | 27.849101 | 27.850581 |
| 4 | 53.635309 | 53.639488 |
| 5 | -37.040125 | -37.042014 |
| 6 | 53.190280 | 53.191362 |
img = np.zeros((200, 200), np.uint8)
cv2.putText(img, '&', (35, 150), font, 5, 255, 15, cv2.LINE_AA)
show_(img, 2)
img2 = img[:, ::-1]
show_(img2, 2)
# 三種誤差函數
print(cv2.matchShapes(img, img2, cv2.CONTOURS_MATCH_I1, 0))
print(cv2.matchShapes(img, img2, cv2.CONTOURS_MATCH_I2, 0))
print(cv2.matchShapes(img, img2, cv2.CONTOURS_MATCH_I3, 0))
print('========================================================')
HuM = get_HuM(img)
rev_HuM = get_HuM(img2)
df = pd.DataFrame.from_dict({'HuM':HuM[:, 0], 'rev_HuM':rev_HuM[:, 0]})
df.head(7)
0.0 0.0 0.0 ========================================================
| HuM | rev_HuM | |
|---|---|---|
| 0 | 6.815878 | 6.815878 |
| 1 | 17.904620 | 17.904620 |
| 2 | 22.489218 | 22.489218 |
| 3 | 27.849101 | 27.849101 |
| 4 | 53.635309 | 53.635309 |
| 5 | -37.040125 | -37.040125 |
| 6 | 53.190280 | -53.190280 |
cv2.calcHist(imgs, channels, mask, histSize, ranges) # 分布線¶imgs: [img](list)channels: [c] 0, 1, 2 對應 B, G, R, [0,1](2D)mask: 全圖設定 NonehistSize: 等高線數目 [256], [180, 256](2D)ranges: 範圍 [0, 256], [0, 180, 0, 256](2D)for c in range(3):
plt.hist(img[:, :, c].ravel(), 256, [0, 256], color=colors[c], alpha=0.6)
plt.xticks([]), plt.yticks([])
cv2.equalizeHist(img) # 分布均勻化¶
# 寫個函數方便用
def color_hist(img, h=6, w=10):
colors = ['b', 'g', 'r']
plt.figure(figsize=(w, h))
for c in range(3):
hist = cv2.calcHist([img], [c], None, [256], [0, 256])
plt.plot(hist, c=colors[c])
plt.xticks([]), plt.yticks([])
plt.show()
img = cv2.imread('data/fig1.jpg')
show_(img, 4)
color_hist(img, 4, 6)
B, G, R = cv2.split(img)
eqB = cv2.equalizeHist(B)
eqG = cv2.equalizeHist(G)
eqR = cv2.equalizeHist(R)
img = cv2.merge((eqB, eqG, eqR))
show_(img, 4)
color_hist(img, 4, 6)
createCLAHE(clipLimit(float), tileGridSize=Size(8, 8)) 自適應亮度均勻¶img = cv2.imread('data/p3.png', 0)
show_(img, 5)
# 雕像部份失去細節
eqh = cv2.equalizeHist(img)
show_(eqh, 5)
# create a CLAHE object (Arguments are optional).
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
cl1 = clahe.apply(img)
show_(cl1, 5)
img = cv2.imread('data/fig2.jpg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# H(0~179) S(0~255) V(0~255)
hist = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
show_(img, 4)
color_hist(hsv, 4, 6) # plot func
plt.imshow(hist, cmap=matplotlib.cm.hsv)
<matplotlib.image.AxesImage at 0x1fa042503d0>
cv2.normalize(img, dst, alpha=1, beta=0, norm_type=cv2.NORM_L2) # 正規化¶Norm Typescv2.normalize(img, dst, min, max, cv2.NORM_MINMAX) 線性縮放dst : 可放入img 直接轉換arr = np.uint8(np.random.normal(96, 10, (20000)))
plt.hist(arr, 128, [0, 256], alpha=0.6)
cv2.normalize(arr, arr, 0 , 255, cv2.NORM_MINMAX)
plt.hist(arr, 128, [0, 256], alpha=0.6)
plt.show()
cv2.calcBackProject(imgs, channels, hist, ranges, scale)¶imgs: [img](list)channels: [c] (0, 1, 2) 對應 (B, G, R) or (H, S, V), [0,1](2D)hist: 由cv2.calcHist 算出的 2D資料(float32), 需要正規化(線性縮放)(0~255) 不然影響後面的運算最大值, 這裡資料格式一定要float32, 不然差異很大ranges: 範圍 [0, 256], [0, 180, 0, 256](2D)# numpy
target = cv2.imread('data/tiger.jpg')
hsvt = cv2.cvtColor(target, cv2.COLOR_BGR2HSV)
roi = target[:690, 950:]
hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
# Find the histograms using calcHist. Can be done with np.histogram2d also
M = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
I = cv2.calcHist([hsvt], [0, 1], None, [180, 256], [0, 180, 0, 256])
# M 是擷取自 I, 一定比較小, R.max()<=1
R = M / I # 會有除以0的報錯 nan
R = np.nan_to_num(R) # np.nan 轉成0
# 把所有點位在新的R中轉換值, 有沒有突出的值, 設定濾鏡
h, s, v = cv2.split(hsvt)
B = R[h.ravel(), s.ravel()]
B = B.reshape(hsvt.shape[:2])
cv2.normalize(B, B, 0, 255, cv2.NORM_MINMAX) # 線性縮放
B = np.uint8(B)
# 主要是把分散的點位連接在一起, 基本上是膨脹操作
disc = np.ones((3, 3))
B = cv2.filter2D(B, -1, disc)
ret, thresh = cv2.threshold(B, 50, 255, cv2.THRESH_BINARY)
# thresh = ~thresh # 變成老虎mask
thresh = cv2.merge((thresh, thresh, thresh))
show_(thresh, 5)
res = cv2.bitwise_and(target, thresh)
show_(res, 5)
C:\Users\Pool\AppData\Local\Temp\ipykernel_9432\1689643170.py:12: RuntimeWarning: invalid value encountered in true_divide R = M / I # 會有除以0的報錯 nan
target = cv2.imread('data/tiger.jpg')
hsvt = cv2.cvtColor(target, cv2.COLOR_BGR2HSV)
roi = target[:690, 950:]
hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
# calculating object histogram
roihist = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
# normalize histogram and apply backprojection
cv2.normalize(roihist, roihist, 0, 255, cv2.NORM_MINMAX) # 線性縮放
dst = cv2.calcBackProject([hsvt], [0, 1], roihist, [0, 180, 0, 256], 1)
show_(dst, 5)
# 主要是把分散的點位連接在一起, 基本上是膨脹操作
disc = np.ones((5, 5))
cv2.filter2D(dst, -1, disc, dst)
# threshold and binary AND
ret, thresh = cv2.threshold(dst, 50, 255, 0)
thresh = cv2.merge((thresh, thresh, thresh))
res = cv2.bitwise_and(target, thresh)
show_(thresh, 5)
show_(res, 5)
cv2.calcBackProject 輸入必須是np.float32 輸出np.uint8¶target = cv2.imread('data/gg.png')
hsvt = cv2.cvtColor(target, cv2.COLOR_BGR2HSV)
roi = target[250:650, 425:925]
hsv = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
M = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
max_val = 255
cv2.normalize(M, M, 0, max_val, cv2.NORM_MINMAX) # 線性縮放
M = np.round(M) # 即使使用的整數
# M = np.uint8(M) # 變化很大
img_info(M, 'M')
#numpy
h, s, v = cv2.split(hsvt)
B1 = M[h.ravel(), s.ravel()]
B1 = B1.reshape(hsvt.shape[:2])
B1 = np.minimum(B1, 255) # 若是 M.max() > 255 == 255
B1 = np.uint8(B1) # 主動轉成 uint8 完全一樣
# openCV
B2 = cv2.calcBackProject([hsvt], [0, 1], M, [0, 180, 0, 256], 1)
# info
img_info(B1, 'B1')
show_(B1)
img_info(B2, 'B2')
show_(B2)
print('B1 Same B2? ', np.all(B1 == B2))
M shape: (180, 256) min: 0.0 max: 255.0 mean: 0.3102864623069763 std: 4.422047138214111 dtype: float32 B1 shape: (935, 1337) min: 0 max: 255 mean: 19.55251880857055 std: 40.741181745618015 dtype: uint8
B2 shape: (935, 1337) min: 0 max: 255 mean: 19.55251880857055 std: 40.741181745618015 dtype: uint8
B1 Same B2? True
- 不同曝光度的照片合成
# Loading exposure images into a list
img_fn = ['HDR-4.jpeg', 'HDR-2.jpeg', 'HDR+2.jpeg', 'HDR+4.jpeg']
img_list = [cv2.imread('data/'+fn) for fn in img_fn]
exposure_times = np.array([15.0, 2.5, 0.25, 0.0333], dtype=np.float32)
# Merge exposures to HDR image
merge_debevec = cv2.createMergeDebevec()
hdr_debevec = merge_debevec.process(img_list, times=exposure_times.copy())
merge_robertson = cv2.createMergeRobertson()
hdr_robertson = merge_robertson.process(img_list, times=exposure_times.copy())
# Tonemap HDR image
tonemap1 = cv2.createTonemap(gamma=2.2)
res_debevec = tonemap1.process(hdr_debevec.copy())
# Exposure fusion using Mertens
merge_mertens = cv2.createMergeMertens()
res_mertens = merge_mertens.process(img_list)
# Convert datatype to 8-bit and save
res_debevec_8bit = np.clip(res_debevec * 255, 0, 255).astype('uint8')
# res_robertson_8bit = np.clip(res_robertson * 255, 0, 255).astype('uint8')
res_mertens_8bit = np.clip(res_mertens * 255, 0, 255).astype('uint8')
# cv2.imwrite("ldr_debevec.jpg", res_debevec_8bit)
# cv2.imwrite("ldr_robertson.jpg", res_robertson_8bit)
# cv2.imwrite("fusion_mertens.jpg", res_mertens_8bit)
cv2.getOptimalDFTSize(num)cv2.dft(img, flags=0)¶np.fft.fft2cv2.idft(img, flags=0)¶np.fft.ifft2DftFlags # 輸出類型¶cv2.magnitude(real-array, imag-array) # 同複數絕對值¶np.fft.fftshift() # 轉換排序¶5432112345 --> 1234554321 一維二維都可以img = np.fft.fftshift(np.fft.fftshift(img)) 轉換兩次恢復img = cv2.imread('data/tiger.jpg', 0)
ft = np.fft.fft2(img)
ft_sft = np.fft.fftshift(ft)
show_(img, 4)
plt.imshow(np.log(np.abs(ft_sft)), cmap=matplotlib.cm.hsv_r) # 複數絕對值
plt.xticks([]), plt.yticks([])
plt.show()
img = cv2.imread('data/tiger.jpg', 0)
ft = np.fft.fft2(img)
ft_sft = np.fft.fftshift(ft)
show_(img, 4)
plt.imshow(np.log(np.abs(ft_sft)), cmap=matplotlib.cm.hsv_r) # 複數絕對值
plt.xticks([]), plt.yticks([])
plt.show()
rows, cols = img.shape
crow, ccol = rows // 2, cols // 2
# 過濾高頻
r = 5
ft_sft[crow - r:crow + r + 1, ccol - r:ccol + r + 1] = 0
ift = np.fft.ifft2(np.fft.fftshift(ft_sft))
img_back = ift.real
plt.imshow(img_back, cmap='gray')
plt.xticks([]), plt.yticks([])
plt.show()
dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
magnitude_spectrum = np.log(cv2.magnitude(dft_shift[:, :, 0], dft_shift[:, :, 1]))
plt.imshow(magnitude_spectrum, cmap=matplotlib.cm.hsv_r)
plt.xticks([]), plt.yticks([])
plt.show()
# create a mask first, center square is 1, remaining all zeros
mask = np.ones((rows, cols, 2), np.uint8)
mask[crow - r:crow + r, ccol - r:ccol + r] = 0
# apply mask and inverse DFT
fshift = dft_shift * mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = img_back[:, :, 0] # 取 real
# img_back = cv2.magnitude(img_back[:, :, 0], img_back[:, :, 1])
plt.imshow(img_back, cmap='gray')
plt.xticks([]), plt.yticks([])
plt.show()
# 低頻濾波
show_(img, 4)
dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT)
# create a mask first, center square is 1, remaining all zeros
r = 300
mask = np.ones((rows, cols, 2), np.uint8)
mask[crow - r:crow + r, ccol - r:ccol + r] = 0
# apply mask and inverse DFT
dft = (dft * mask)
img_back = cv2.idft(dft)
img_back = img_back[:, :, 0] # 取 real
# dft img
magnitude_spectrum = np.log(cv2.magnitude(dft[:, :, 0], dft[:, :, 1]))
plt.imshow(magnitude_spectrum, cmap=matplotlib.cm.hsv_r)
plt.xticks([]), plt.yticks([])
plt.show()
# img_back = cv2.magnitude(img_back[:, :, 0], img_back[:, :, 1])
plt.imshow(img_back, cmap='gray')
plt.xticks([]), plt.yticks([])
plt.show()
C:\Users\Pool\AppData\Local\Temp\ipykernel_9432\2424722692.py:16: RuntimeWarning: divide by zero encountered in log magnitude_spectrum = np.log(cv2.magnitude(dft[:, :, 0], dft[:, :, 1]))
cv2.matchTemplate(img, temp, method)¶TemplateMatchModescv2.minMaxLoc(img)¶minVal, maxVal, minLoc, maxLoco_img = cv2.imread('data/mario.png')
template = o_img[480:560, 1030:1150]
print('find castle:')
show_(template, 5)
img_g = cv2.cvtColor(o_img, cv2.COLOR_BGR2GRAY)
template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
h, w = template.shape
# All the 6 methods for comparison in a list
methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR', 'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']
for meth in methods:
img2 = img_g.copy()
method = eval(meth)
# Apply template Matching
res = cv2.matchTemplate(img2, template, method)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
print('max:', max_val)
print('min:', min_val)
# If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum 這兩種取最小值
if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
top_left = min_loc
else:
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
img = o_img.copy()
cv2.rectangle(img, top_left, bottom_right, (0, 0, 255), 10)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.figure(figsize=(15, 5))
plt.subplot(121), plt.imshow(res, cmap='gray')
plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(img, cmap='gray')
plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
plt.suptitle(meth)
plt.show()
find castle:
max: 90822264.0 min: -34178016.0
max: 1.0 min: -0.36539873480796814
max: 246287072.0 min: 16918500.0
max: 1.0 min: 0.16528712213039398
max: 291866304.0 min: 0.0
max: 1.0 min: 0.0
img_rgb = cv2.imread('data/mario.png')
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template_rgb = img_rgb[491:556, 306:410]
show_(template_rgb, 4)
template = cv2.cvtColor(template_rgb, cv2.COLOR_BGR2GRAY)
w, h = template.shape[::-1]
res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
threshold = 0.8 # 相似度設定
loc = np.where(res >= threshold) # 回傳True 的index
for pt in zip(*loc[::-1]):
cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (255, 25, 25), 2)
show_(img_rgb)
cv2.HoughLines(image, ρ(像素最小單位), θ(角度最小單位), threshold)¶ρ, θimg: 吃二值化圖片threshold: 閥值(累積數目, 那條線有幾個點)cv2.HoughLinesP(image, ρ(像素最小單位), θ(角度最小單位), threshold, minLineLength, maxLineGap)¶minLineLength: 最短線條設定maxLineGa: 線條最大間隔# Numpy code
img = cv2.imread('data/hough.png', 0)
img = cv2.resize(img, (400, 300))
img = cv2.threshold(img, 100, 255, cv2.THRESH_BINARY)[1]
show_(img, 4)
coor = np.where(img == 255)
x = coor[0] + 1
y = coor[1] + 1
θ = np.linspace(0, 180, num=180, endpoint=False)
sinθ = np.sin(np.deg2rad(θ))
cosθ = np.cos(np.deg2rad(θ))
ρ = (x.reshape((-1, 1)) * cosθ) + (y.reshape((-1, 1)) * sinθ)
arr = np.zeros((1000, 180))
for θ_ in range(180):
for ρ_ in ρ[:, θ_]:
arr[int(500 + ρ_), θ_] += 1
plt.imshow(cv2.resize(arr, (180, 180)), cmap=matplotlib.cm.hsv)
<matplotlib.image.AxesImage at 0x1fa0374d670>
img = cv2.imread('data/dave.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 0, 100, apertureSize=3)
show_(edges, 5)
lines = cv2.HoughLines(edges, 1, np.pi / 720, 180)
for line in lines:
ρ, θ = line[0]
a = np.cos(θ)
b = np.sin(θ)
x0 = a * ρ
y0 = b * ρ
x1 = int(x0 + 1000 * (-b))
y1 = int(y0 + 1000 * (a))
x2 = int(x0 - 1000 * (-b))
y2 = int(y0 - 1000 * (a))
cv2.line(img, (x1, y1), (x2, y2), (25, 255, 25), 2)
show_(img, 5)
lines = cv2.HoughLinesP(edges, 1, np.pi / 180, 100, minLineLength=100, maxLineGap=20)
for line in lines:
x1, y1, x2, y2 = line[0]
cv2.line(img, (x1, y1), (x2, y2), (0, 255, 0), 1)
show_(img, 5)
cv2.HoughCircles(image, method, dp, minDist, param1, param2, minRadius, maxRadius)¶methodimg = cv2.imread('data/p1.png', 0) - 1
img = cv2.medianBlur(img, 5) # 中位數濾鏡
cimg = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0, maxRadius=0)
circles = np.uint16(np.around(circles))
for i in circles[0, :]:
# draw the outer circle
cv2.circle(cimg, (i[0], i[1]), i[2], (0, 255, 0), 2)
# draw the center of the circle
cv2.circle(cimg, (i[0], i[1]), 2, (0, 0, 255), 2)
show_(cimg, 5)
cv2.watershed(image, markers)¶img = cv2.imread('data/coins.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Otsu's 二值化
ret, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
show_(thresh)
# noise removal 開運算 吃掉白色小雜訊
kernel = np.ones((3, 3), np.uint8)
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)
show_(opening)
# sure background area 膨脹
sure_bg = cv2.dilate(opening, kernel, iterations=3)
show_(sure_bg)
# Finding sure foreground area
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
ret, sure_fg = cv2.threshold(dist_transform, 0.7 * dist_transform.max(), 255, 0)
show_(sure_fg)
# Finding unknown region
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg)
show_(unknown)
# Marker labelling
ret, markers = cv2.connectedComponents(sure_fg)
# Add one to all labels so that sure background is not 0, but 1
markers = markers + 1
# Now, mark the region of unknown with zero
markers[unknown == 255] = 0
markers = cv2.watershed(img, markers)
img[markers == -1] = [255, 0, 0]
show_(img)
min: 0.00, PR1.5: 0.00, PR98.5: 255.00, max: 255.00
cv2.grabCut(img, mask, rect, bgdModel, fgdModel, iterCount, mode)¶img = cv2.imread('data/meat.jpg')
img = cv2.resize(img, None, fx=0.25, fy=0.25, interpolation=cv2.INTER_AREA)
show_(img, 5)
mask = np.zeros(img.shape[:2], np.uint8)
bgdModel = np.zeros((1, 65), np.float64)
fgdModel = np.zeros((1, 65), np.float64)
rect = (80, 60, 640, 400) # img[60:400, 80:640]
cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_RECT)
mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')
img = img * mask2[:, :, np.newaxis]
show_(img, 5)
cv2.cornerHarris(img, blockSize, ksize, k)¶img 需要轉為 np.float32() 格式blockSize 角檢測需要考慮的大小(u, v ???)ksize 檢測 filter大小(奇數)k (0.04~0.06)img = cv2.imread('data/corner.jpg')
# img = cv2.resize(img, (640, 480))
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = np.float32(gray)
# 输入图像必 是 float32 最后一个参数在 0.04 到 0.06 之间
dst = cv2.cornerHarris(gray, 2, 3, 0.05)
# result is dilated for marking the corners, not important
dst = cv2.dilate(dst, None) # 腐蝕
# Threshold for an optimal value, it may vary depending on the image.
img_info(dst)
img[dst > 0.01 * dst.max()] = [25, 255, 25]
show_(img, 5)
shape: (256, 256) min: -2704608.5 max: 7150541.0 mean: 8294.1455078125 std: 225383.078125 dtype: float32
cv2.goodFeaturesToTrack(img, maxCorners, qualityLevel, minDistance, corners, mask, blockSize, useHarrisDetector, k)maxCorners: N (-1 所有的角)qualityLevel:(float) 質量等級minDistance: 角度的歐基里得距離mask: 檢測範圍設定blockSize: 角檢測需要考慮的大小(u, v ???)useHarrisDetector: 使用Harris檢測k: Harris的參數img = cv2.imread('data/corner.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
corners = cv2.goodFeaturesToTrack(gray, 50, 0.01, 5)
for i in corners:
x, y = i[0]
# cv2.circle(img, center, radius, color, thickness)
cv2.circle(img, (int(x), int(y)), 3, (25, 255, 14), -1)
show_(img)

pip install opencv-contrib-python==3.4.2.17 需要安裝舊一點版本cv2.drawKeypoints(img, keypoints, out_img, color, flags)¶keypoints (list), kp-dataanglept 座標sizeflag- DRAW_MATCHES_FLAGS

img = cv2.imread('data/corner.jpg', 0)
# Initiate FAST object with default values
fast = cv2.FastFeatureDetector_create()
# find and draw the keypoints
kp = fast.detect(img, None)
img2 = cv2.drawKeypoints(img, kp, None, color=(225, 0, 0))
# Print all default params
print(f"Threshold: {fast.getThreshold()}")
print(f"nonmaxSuppression:{fast.getNonmaxSuppression()}")
print(f"neighborhood: {fast.getType()}")
print(f"Total Keypoints with nonmaxSuppression: {len(kp)}")
show_(img2, 5)
# Disable nonmaxSuppression
fast.setNonmaxSuppression(0)
kp = fast.detect(img, None)
print(f"Total Keypoints with nonmaxSuppression: {len(kp)}")
img3 = cv2.drawKeypoints(img, kp, None, color=(225, 0, 0))
show_(img3, 5)
Threshold: 10 nonmaxSuppression:True neighborhood: 2 Total Keypoints with nonmaxSuppression: 431
Total Keypoints with nonmaxSuppression: 1575
img = cv2.imread('data/corner.jpg', 0)
# Initiate STAR detector
orb = cv2.ORB_create()
# find the keypoints with ORB
kp = orb.detect(img, None)
# compute the descriptors with ORB
kp, des = orb.compute(img, kp)
print(f'kp_num: {len(kp)}')
print(f'des.shape: {des.shape}')
# draw only keypoints location,not size and orientation
img2 = cv2.drawKeypoints(img, kp[:10], None, color=(0, 255, 0), flags=0)
show_(img2)
kp_num: 290 des.shape: (290, 32)
show_(des)
cv2.BFMatcher(normType(int), crossCheck (bool))¶crossCheck: 預設Falsebf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) 創建一個BF-Matcher 物件bf.match()bf.knnMatch()matches = bf.match(des1, des2) matches物件的屬性.distance 描述向量的距離 越小越好.trainIdx 目標圖像描述向量的index.queryIdx 查詢圖像描述向量的index.imgIdx 目標圖像的index (0)cv2.drawMatches(img1, keypoints1, img2, keypoints2, matches1to2, outImg, matchColor, singlePointColor, matchesMask, flags)¶img1 = cv2.imread('data/JD1.jpg')
img2 = cv2.imread('data/JD2.jpg')
orb = cv2.ORB_create()
# find the keypoints and descriptors with ORB
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)
# create BFMatcher object
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
# Match descriptors.
matches = bf.match(des1, des2)
# Sort them in the order of their distance.
matches = sorted(matches, key=lambda x: x.distance)
# Draw first 10 matches.
img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:200], None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
show_(img3, 10)
cv2.FlannBasedMatcher(indexParams, searchParams)¶# wait
image = cv2.imread('data/pool.jpg')
h, w = image.shape[:2]
r = h / w
w = 400
h = int(r * w)
image = cv2.resize(image, (w, h), interpolation=cv2.INTER_CUBIC)
# 導入模型和設定
net = cv2.dnn.readNetFromCaffe('data/deploy.prototxt.txt', 'data/face_detection.caffemodel')
blob = cv2.dnn.blobFromImage(cv2.resize(image, (300, 300)), 1.0, (300, 300), (104.0, 177.0, 123.0))
# pass the blob through the network and obtain the detections and
# predictions
net.setInput(blob)
detections = net.forward()
# loop over the detections
for i in range(0, detections.shape[2]):
# extract the confidence (i.e., probability) associated with the
# prediction
confidence = detections[0, 0, i, 2]
# filter out weak detections by ensuring the `confidence` is
# greater than the minimum confidence
# 機率大於多少畫框框
if confidence > 0.15:
# compute the (x, y)-coordinates of the bounding box for the
# object
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
(startX, startY, endX, endY) = box.astype("int")
# draw the bounding box of the face along with the associated
# probability
text = "{:.2f}%".format(confidence * 100)
y = startY - 10 if startY - 10 > 10 else startY + 10
cv2.rectangle(image, (startX, startY), (endX, endY), (0, 225, 0), 3)
cv2.putText(image, text, (startX, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 225, 225), 2)
# show the output image
show_(image, 10)
cv2.VideoCapture(index(int), filename)¶cv2.VideoCapture(0) 預設攝影機cv2.VideoCapture(filename) 打開影片檔案cap = cv2.VideoCapture(file_name)frame (np.array) 畫面 沒有輸出Nonecap.isOpened() (bool) 檢查初始化是復成功cap.open(filename) 可以重新開啟檔案ret, frame = cap.read() 一次讀取一幀ret bool 有沒有資料(讀取正確)cap.get(propId) propId(0~18) 取得影片的屬性
| id | --- | 影片 | 相機 |
|---|---|---|---|
| 0 | 影片當前位置(ms) | v | v |
| 1 | 影片當下幀的index(float) | v | -1 |
| 2 | 影片相對位置(0~1) | v | -1 |
| 3 | 寬度 | v | v |
| 4 | 高度 | v | v |
| 5 | 幀數(FPS) | v | v |
| 6 | 解碼器的4位字符 | ||
| 7 | 影片幀數(總幀數) | v | -1 |
| 10 | 亮度 | 0 | v |
| 11 | 對比度 | 0 | v |
| 12 | 飽和度 | 0 | v |
| 13 | 色相 | 0 | v |
cap.set(propId, value) 設定新的屬性cap.release() 關閉cv2.VideoWriter(filename, fourcc, fps, frameSize, isColor(bool))¶fourcc 編碼形式 (四節字碼)fourcc = cv2.VideoWriter_fourcc(*'XVID')out = cv2.VideoWriter('file_name', fourcc, fps(int), size(640, 480))cap = cv2.VideoCapture(0) # 設定0 筆電攝影機
if not cap.isOpened():
print("Cannot open camera")
while True:
# Capture frame-by-frame
ret, frame = cap.read()
# if frame is read correctly ret is True
if ret: # ret == True
# 上文字
t = 'time: ' + str(cap.get(0) // 1000)
fps = 'fps: '+ str(cap.get(5))
w = 'w: ' + str(cap.get(3))
h = 'h: ' + str(cap.get(4))
texts = [t, fps, w, h]
for i in range(4):
cv2.putText(frame, texts[i], (10, (i + 1) * 30), font, 0.8, (0, 255, 0), 2, cv2.LINE_AA)
# Display the resulting frame
cv2.imshow('frame', frame)
if cv2.waitKey(10) & 0xFF == ord('q'): # q 退出
break
else:
print("Can't receive frame (stream end?). Exiting ...")
break
# When everything done, release the capture
cap.release() # 關閉攝影積
cv2.destroyAllWindows()
cap = cv2.VideoCapture('data/soupO.mp4')
while cap.isOpened():
ret, frame = cap.read()
# if frame is read correctly ret is True
if not ret:
print("Can't receive frame (stream end?). Exiting ...")
break
# 上文字
t = 'time: ' + str(round(cap.get(0) / 1000, 1))
fps = 'fps: '+ str(cap.get(5))
w = 'w: ' + str(cap.get(3))
h = 'h: ' + str(cap.get(4))
texts = [t, fps, w, h]
for i in range(4):
cv2.putText(frame, texts[i], (10, (i + 1) * 30), font, 0.8, (0, 255, 0), 2, cv2.LINE_AA)
cv2.imshow('frame', frame)
if cv2.waitKey(40) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
for i in [i for i in dir(cv2) if i.startswith('COLOR_BGR2')]:
print(i)
COLOR_BGR2BGR555 COLOR_BGR2BGR565 COLOR_BGR2BGRA COLOR_BGR2GRAY COLOR_BGR2HLS COLOR_BGR2HLS_FULL COLOR_BGR2HSV COLOR_BGR2HSV_FULL COLOR_BGR2LAB COLOR_BGR2LUV COLOR_BGR2Lab COLOR_BGR2Luv COLOR_BGR2RGB COLOR_BGR2RGBA COLOR_BGR2XYZ COLOR_BGR2YCR_CB COLOR_BGR2YCrCb COLOR_BGR2YUV COLOR_BGR2YUV_I420 COLOR_BGR2YUV_IYUV COLOR_BGR2YUV_YV12
cv2.inRange(img, lower_val, upper_val)¶arr = np.arange(10).reshape(5, 1, 2)
print(arr)
cv2.inRange(arr, (0, 3), (6, 9))
[[[0 1]] [[2 3]] [[4 5]] [[6 7]] [[8 9]]]
array([[ 0],
[255],
[255],
[255],
[ 0]], dtype=uint8)
# 顯示藍色的物體!!
cap = cv2.VideoCapture(0)
while cap.isOpened():
# Take each frame
_, frame = cap.read()
# Convert BGR to HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# define range of blue color in HSV # 轉換成HSV方便找到顏色
lower_blue = np.array([70, 30, 30])
upper_blue = np.array([160, 255, 255])
# Threshold the HSV image to get only blue colors
mask = cv2.inRange(hsv, lower_blue, upper_blue)
# Bitwise-AND mask and original image
res = cv2.bitwise_and(frame, frame, mask=mask)
cv2.imshow('frame', frame)
cv2.imshow('mask', mask)
cv2.imshow('res', res)
k = cv2.waitKey(20) & 0xFF
if k == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
# backSub = cv2.createBackgroundSubtractorKNN()
backSub = cv2.createBackgroundSubtractorMOG2()
cap = cv2.VideoCapture(0)
while cap.isOpened():
ret, frame = cap.read()
if frame is None:
print('break')
break
fgMask = backSub.apply(frame)
cv2.rectangle(frame, (10, 2), (100, 20), (255, 255, 255), -1)
# cv2.putText(frame, str(cap.get(cv2.CAP_PROP_POS_FRAMES)), (15, 15), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 0))
cv2.imshow('Frame', frame)
cv2.imshow('FG Mask', fgMask)
if cv2.waitKey(20) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
cap = cv2.VideoCapture('data/slow_traffic.mp4')
fps = cap.get(cv2.CAP_PROP_FPS)
wait_ = round(1000 / fps)
# take first frame of the video
ret, frame = cap.read()
# setup initial location of window
x, y, w, h = 300, 190, 90, 60 # simply hardcoded the values
track_window = (x, y, w, h)
# set up the ROI for tracking
roi = frame[y:y + h, x:x + w]
hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv_roi, (0, 0, 150), (180, 100, 255)) # 白色的過濾
# show_(mask)
roi_hist = cv2.calcHist([hsv_roi], [1, 2], mask, [255, 255], [0, 255, 0, 255])
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (17, 17))
roi_hist = cv2.filter2D(roi_hist, -1, kernel) # 模糊化 讓附近比的比較容易抓到
cv2.normalize(roi_hist, roi_hist, 0, 255, cv2.NORM_MINMAX) # 線性縮放 0~255
# show_(roi_hist)
# Setup the termination criteria, either 10 iteration or move by atleast 1 pt
term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)
while cap.isOpened():
ret, frame = cap.read()
if not ret:
print('end')
break
if cv2.waitKey(wait_) & 0xFF == ord('q'):
break
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
dst = cv2.calcBackProject([hsv], [1, 2], roi_hist, [0, 255, 0, 255], 1)
cv2.imshow('dst', dst)
# apply meanshift to get the new location
ret, track_window = cv2.meanShift(dst, track_window, term_crit)
# Draw it on image
x, y, w, h = track_window
img2 = cv2.rectangle(frame, (x, y), (x + w, y + h), (25, 255, 25), 2)
cv2.putText(img2, f'x:{x}, y:{y}, w:{w}, h:{h}', (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2, cv2.LINE_AA)
cv2.imshow('img2', img2)
cap.release()
cv2.destroyAllWindows()
cap = cv2.VideoCapture('data/slow_traffic.mp4')
fps = cap.get(cv2.CAP_PROP_FPS)
wait_ = round(1000 / fps)
# take first frame of the video
ret, frame = cap.read()
# setup initial location of window
x, y, w, h = 300, 190, 90, 60 # simply hardcoded the values
track_window = (x, y, w, h)
# set up the ROI for tracking
roi = frame[y:y + h, x:x + w]
hsv_roi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(hsv_roi, (0, 0, 150), (180, 100, 255)) # 白色的過濾
# show_(mask)
roi_hist = cv2.calcHist([hsv_roi], [1, 2], mask, [255, 255], [0, 255, 0, 255])
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (17, 17))
roi_hist = cv2.filter2D(roi_hist, -1, kernel) # 模糊化 讓附近比的比較容易抓到
cv2.normalize(roi_hist, roi_hist, 0, 255, cv2.NORM_MINMAX) # 線性縮放 0~255
# show_(roi_hist)
# Setup the termination criteria, either 10 iteration or move by atleast 1 pt
term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)
while cap.isOpened():
ret, frame = cap.read()
if not ret:
print('end')
break
if cv2.waitKey(wait_) & 0xFF == ord('q'):
break
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
dst = cv2.calcBackProject([hsv], [1, 2], roi_hist, [0, 255, 0, 255], 1)
cv2.imshow('dst', dst)
# apply camshift to get the new location
ret, track_window = cv2.CamShift(dst, track_window, term_crit)
# Draw it on image
pts = cv2.boxPoints(ret)
pts = np.int0(pts)
img2 = cv2.polylines(frame, [pts], True, (0, 255, 0), 2)
cv2.imshow('img2', img2)
cap.release()
cv2.destroyAllWindows()
ball = cv2.imread('data/bule_ball.jpg')
# show_(ball)
ball_hsv = cv2.cvtColor(ball, cv2.COLOR_BGR2HSV)
mask = cv2.inRange(ball_hsv, (70, 150, 100), (160, 255, 255))
# show_(mask)
ball_hist = cv2.calcHist([ball_hsv], [0, 1], mask, [180, 255], [0, 180, 0, 255])
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (11, 15))
ball_hist = cv2.filter2D(ball_hist, -1, kernel) # 模糊化 讓附近比的比較容易抓到
cv2.normalize(ball_hist, ball_hist, 0, 255, cv2.NORM_MINMAX) # 線性縮放 0~255
# show_(ball_hist)
term_crit = (cv2.TERM_CRITERIA_EPS | cv2.TERM_CRITERIA_COUNT, 10, 1)
cap = cv2.VideoCapture(0)
track_window = (100, 100, 100, 100)
while cap.isOpened():
ret, frame = cap.read()
if cv2.waitKey(20) & 0xFF == ord('q'):
break
# Convert BGR to HSV
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
# Threshold the HSV image to get only blue colors
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
dst = cv2.calcBackProject([hsv], [0, 1], ball_hist, [0, 180, 0, 255], 1)
cv2.imshow('dst', dst)
ret, track_window = cv2.CamShift(dst, track_window, term_crit)
pts = np.int0(pts)
img2 = cv2.polylines(frame, [pts], True, (0, 255, 255), 2)
cv2.imshow('frame', frame)
cap.release()
cv2.destroyAllWindows()
cv2.calcOpticalFlowPyrLK(prevImg, nextImg, prevPts, nextPts)¶cv2.goodFeaturesToTrack(img, maxCorners, qualityLevel, minDistance, corners, mask, blockSize, useHarrisDetector, k)¶maxCorners: N (-1 所有的角)qualityLevel:(float) 質量等級minDistance: 角度的歐基里得距離mask: 檢測範圍設定blockSize: 角檢測需要考慮的大小(u, v ???)useHarrisDetector: 使用Harris檢測k: Harris的參數cap = cv2.VideoCapture('data/slow_traffic.mp4')
fps = cap.get(cv2.CAP_PROP_FPS)
wait_ = round(1000 / fps)
# params for ShiTomasi corner detection & lucas kanade optical flow
feature_params = {'maxCorners': 100, 'qualityLevel': 0.3, 'minDistance': 7, 'blockSize': 7}
# maxLevel 为使用的图像金字塔层数
lk_params = {'winSize': (15, 15), 'maxLevel': 2, 'criteria': (3, 10, 0.03)}
# Create some random colors
color = np.random.randint(0, 255, size=(100, 3))
# Take first frame and find corners in it
ret, old_frame = cap.read()
old_gray = cv2.cvtColor(old_frame, cv2.COLOR_BGR2GRAY) # 轉灰度
p0 = cv2.goodFeaturesToTrack(old_gray, mask=None, **feature_params)
# Create a mask image for drawing purposes
mask = np.zeros_like(old_frame)
while cap.isOpened():
ret, frame = cap.read()
if not ret:
print('end')
break
if cv2.waitKey(wait_) & 0xFF == ord('q'):
break
frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# calculate optical flow
p1, st, err = cv2.calcOpticalFlowPyrLK(old_gray, frame_gray, p0, None, **lk_params)
# Select good points
good_new = p1[st == 1]
good_old = p0[st == 1]
# draw the tracks
for i, (new, old) in enumerate(zip(good_new, good_old)):
a, b = new.ravel()
c, d = old.ravel()
mask = cv2.line(mask, (int(a), int(b)), (int(c), int(d)), color[i].tolist(), 2)
frame = cv2.circle(frame, (int(a), int(b)), 5, color[i].tolist(), -1)
img = cv2.add(frame, mask)
cv2.imshow('frame', img)
# Now update the previous frame and previous points
old_gray = frame_gray.copy()
p0 = good_new.reshape(-1, 1, 2)
cap.release()
cv2.destroyAllWindows()
cap = cv2.VideoCapture('data/vtest.avi')
fps = cap.get(cv2.CAP_PROP_FPS)
wait_ = round(1000 / fps)
ret, frame1 = cap.read()
prvs = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY)
hsv = np.zeros_like(frame1)
hsv[..., 1] = 255 # arr[..., i or i:j] 取後段
while cap.isOpened():
ret, frame2 = cap.read()
if not ret:
print('end')
break
if cv2.waitKey(wait_) & 0xFF == ord('q'):
break
cv2.imshow('frame2', frame2)
next = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)
flow = cv2.calcOpticalFlowFarneback(
prvs, next, None, 0.5, 3, 15, 3, 5, 1.2, 0)
mag, ang = cv2.cartToPolar(flow[..., 0], flow[..., 1])
hsv[..., 0] = ang * 180 / np.pi / 2
hsv[..., 2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)
bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
cv2.imshow('bgr', bgr)
k = cv2.waitKey(20) & 0xff
if k == ord('q'):
break
elif k == ord('s'):
cv2.imwrite('opticalfb.png', frame2)
cv2.imwrite('opticalhsv.png', bgr)
prvs = next
cap.release()
cv2.destroyAllWindows()
t = cv2.getTickCount()
time.sleep(1)
(cv2.getTickCount() - t) / cv2.getTickFrequency()
1.0114011
t = time.time()
time.sleep(1)
time.time() - t
1.000519037246704
cv2.useOptimized()
True